﻿using LogLib;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;

namespace PassportReader
{ 
    public class PRSDK
    { 
        // 1 表示保存白光全图
        // 2 表示保存红外全图
        // 4 表示保存紫外全图
        // 8 表示保存版面头像
        // 16 表示保存芯片的头像 
        private int _nSaveImage = 1;

        /// <summary>
        /// 电子芯片识别参数（DG1-DG16）
        /// </summary>
        private int _nDG = 0;

        /// <summary>
        /// 核心动态库的路径
        /// </summary>
        private readonly string _dllPath = "";

        private string _error = "";
        public string ErrorMessage
        {
            get { return _error; }
        }

        /// <summary>
        /// 证件类型
        /// </summary>
        private int IDCardType = 13;

        /// <summary>
        /// 当前识别的证件号码结果
        /// </summary>
        private string ReadIDNo = "";

        public PRSDK()
        {        
            InitDGParam();
        }
     
        /// <summary>
        /// 初始化DG参数
        /// </summary>
        private void InitDGParam()
        {
            // 默认识别DG1-DG4参数
            for (int i = 1; i <= 4; i++)
            {
                _nDG |= (1 << (i - 1));
            }
        }

        public bool LoadKernal(string dllDir, string userId)
        {
            if(!ReaderDll.LoadKernal(dllDir, userId))
            {
                _error = ReaderDll.Error;
                return false;
            }
            return true;
        }

        public void FreeKernal()
        {
            ReaderDll.FreeKernal();
        }

        public bool CheckDeviceConnected()
        {
            bool bRet = ReaderDll.CheckDeviceOnline();
            if (bRet)
            {
                Log.WriteAsync("The device is online.");
                return true;
            }
            else
            {
                _error = "The device is offline.";
                Log.WriteAsync(_error);
                return false;
            }
        }

        public bool CheckExistDocument(ref int flag)
        {
            _error = "";
            flag = ReaderDll.DetectDocument();
            if (flag == 1)
            {
                return true;
            }
            else if(flag == 0)
            {
                _error = "SDK未初始化.";
                return false;
            }
            else if (flag == 2)
            {
                _error = "证件被拿出.";
                return false;
            }
            else if (flag == 3)
            {
                _error = "检测到条码.";
                return false;
            }
            else
            {
                _error = "检测存在证件返回未知错误" + flag.ToString();
                return false;
            }
        }

        private void SetRecogType()
        {
            ReaderDll.SetSaveImageType(_nSaveImage);
            ReaderDll.SetRecogVIZ(true);
        }

        private bool SaveImage(string directory, ref JObject job)
        {
            _error = "";
            string strFileName = ReadIDNo;
            StringBuilder rBuilder = new StringBuilder(strFileName);
            foreach (char rInvalidChar in Path.GetInvalidFileNameChars())
            {
                rBuilder.Replace(rInvalidChar.ToString(), string.Empty);
            }               
            string strImagePath = string.Format(@"{0}\{1}.jpg", directory, rBuilder.ToString());
            int nRet = ReaderDll.SaveImageEx(strImagePath, _nSaveImage);
            if (nRet != 0)
            {
                _error = "SaveImageEx fail:" + nRet.ToString();
                Log.WriteAsync(_error);
                return false;
            }
            else
            {
                job.Add("ImagePath", strImagePath);
            }
            return true;
        }

        /// <summary>
        /// 设置读取护照类型的SDK识别ID
        /// </summary>
        public const int PassportID = 13;

        /// <summary>
        /// 设置读取签证类型的SDK识别ID
        /// </summary>
        public const int VisaID = 12;

        private JObject GetRecogResult()
        {
            _error = "";
            int MAX_CH_NUM = 256;
            int nBufLen = MAX_CH_NUM * sizeof(byte);
            ReadIDNo = "";
            JObject job = new JObject();
            int index0 = -1, index1 = -1;
            Log.WriteAsync("GetRecogResult start...");
            for (int i = 0; ; i++)
            {
                string FieldName = new string('\0', MAX_CH_NUM);
                string FieldValue = new string('\0', MAX_CH_NUM);
                int nRet = ReaderDll.GetRecogResultEx(1, i, FieldValue, ref nBufLen);
                if (nRet == 3)
                    break;
                nBufLen = MAX_CH_NUM * sizeof(byte);
                ReaderDll.GetFieldNameEx(1, i, FieldName, ref nBufLen);
                nBufLen = MAX_CH_NUM * sizeof(byte);
                FieldName = FieldName.TrimEnd('\0');
                FieldValue = FieldValue.TrimEnd('\0');
                index0 = FieldName.IndexOf('\0');
                index1 = FieldValue.IndexOf('\0');
                if (index0 >= 0)
                {
                    FieldName = FieldName.Substring(0, index0);
                }
                if (index1 >= 0)
                {
                    FieldValue = FieldValue.Substring(0, index1);
                }
                job.Add(FieldName, FieldValue);
                Log.WriteAsync(FieldName + ":" + FieldValue);

                // 得到护照号码或者证件号码
                if(string.IsNullOrEmpty(ReadIDNo))
                {
                    if (IDCardType == PassportID && FieldName.Contains("护照号码MRZ"))
                    {
                        ReadIDNo = FieldValue;
                    }
                    else if (IDCardType == VisaID && FieldName.Contains("护照号码/通行证号码"))
                    {
                        ReadIDNo = FieldValue;
                    }
                    else if (FieldName.Contains("护照号码")
                        || FieldName.Contains("证件号码") 
                        || FieldName.Contains("MRZ导出号码"))
                    {
                        ReadIDNo = FieldValue;
                    }
                }              
            }
            Log.WriteAsync("GetRecogResult end...");
            return job;
        }

      
        /// <summary>
        /// 护照识别操作
        /// </summary>
        /// <param name="mainID">证件类型</param>
        /// <param name="imgFilePath">传入保存的路径</param>
        /// <param name="dicRecogRet">输出识别结果</param>
        /// <param name="errMsg">错误信息</param>
        /// <returns></returns>
        public bool ScanAndRecog(int mainID, string imgFilePath, out string jsonRecogResult)
        {
            _error= "";
            jsonRecogResult = "";
            IDCardType = mainID;
            int[] nSubID = new int[1];
            nSubID[0] = 0;
            ReaderDll.ResetIDCardID();
            int nRet = ReaderDll.AddIDCardID(mainID, nSubID, 1);
            if (nRet != 0)
            {
                _error = string.Format("Fail to AddIDCardID {0}. Return code:{1}.", mainID, nRet);
                Log.WriteAsync(_error);
                return false;
            }
            //if (mainID == 10)  //本式台胞证
           // {
            nRet = ReaderDll.AddIDCardID(10, nSubID, 1);  //本式台胞证
            if (0 != nRet)
            {
                _error = string.Format("Fail to AddIDCardID 25. Return code:{0}.", nRet);
                Log.WriteAsync(_error);
                return false;
            }

                nRet = ReaderDll.AddIDCardID(25, nSubID, 1);  //卡式台胞证
                if (0 != nRet)
                {
                    _error = string.Format("Fail to AddIDCardID 25. Return code:{0}.", nRet);
                    Log.WriteAsync(_error);
                    return false;
                }

                nRet = ReaderDll.AddIDCardID(14, nSubID, 1);  //回乡证
                if (0 != nRet)
                {
                    _error = string.Format("Fail to AddIDCardID 14. Return code:{0}.", nRet);
                    Log.WriteAsync(_error);
                    return false;
                }

                nRet = ReaderDll.AddIDCardID(22, nSubID, 1);  //港澳通行证
                if (0 != nRet)
                {
                    _error = string.Format("Fail to AddIDCardID 14. Return code:{0}.", nRet);
                    Log.WriteAsync(_error);
                    return false;
                }
           // }

            int nCardType = 0;
            nRet = ReaderDll.AutoProcessIDCard(ref nCardType);
            if (nRet <= 0)
            {             
                _error = string.Format("Fail to read the card. Return code:{0}", nRet);
                Log.WriteAsync(_error);
                return false;
            }
            string strLog = string.Format("识别证件类型为: {0}, 证件主类型: {1}", nCardType, nRet);
            Log.WriteAsync(strLog);
            IDCardType = nRet;
            // 读取识别                     
            JObject result = GetRecogResult();         
            // 保存图片
            if (SaveImage(imgFilePath, ref result))
            {
                jsonRecogResult = result.ToString();
                return true;
            }
            else
            {
                Log.WriteAsync("保存读取照片失败:" + _error);
                return false;
            }
        }

        /// <summary>
        /// 采集证件的资料页照片
        /// </summary>
        /// <param name="imgFilePath">保存照片的完整绝对路径</param>
        /// <returns></returns>
        public bool AcquireAndSaveImage(string imgFilePath)
        {
            _error = "";
            int ret = ReaderDll.AcquireImage(3);
            if (0 != ret)
            {
                _error = "AcquireImage fail:" + ret.ToString();
                Log.WriteAsync(_error);
                return false;
            }
            ret = ReaderDll.SaveImageEx(imgFilePath, _nSaveImage);
            if (ret != 0)
            {
                _error = "SaveImageEx fail:" + ret.ToString();
                Log.WriteAsync(_error);
                return false;
            }
            return true;
        }
    }
}
